import os
from apscheduler.schedulers.blocking import BlockingScheduler

from service.data_service import stock_dict
from service import users_service, trigger_service, score_service
from utils.logger import Logger
from utils import date_util, k_util, ave_util, price_util, caiptal_util, msg_util, doc_util, json_util, read_config, \
    excel_util

stock_monitor_dict = {}  # 需要监控的股票池
users_dict = {}  # 用户字典
frequency_config = 180  # 定时任务时间 单位秒

users_path = os.path.join(read_config.data_path, 'common', 'users')
result_path = os.path.join(read_config.data_path, 'result', '突破均线')
document_path = os.path.join(read_config.data_path, 'task', 'document', '突破均线')

logger = Logger('突破均线任务1').get_log()


def monitor_up_down_v1():
    print("定时任务执行时间" + date_util.get_date_time_str())
    if check_time(): return  # 规避时间段
    if check_update(): return  # 检查配置更新
    current_date = date_util.get_date_str()  # 当前时间串
    # 监控冲破均线
    for code in stock_monitor_dict.keys():
        stock_info = json_util.info_to_json(stock_monitor_dict[code])  # 获取当前字典配置
        rt_price = price_util.get_rt_p(code)  # 股票实时价格
        k_line = k_util.day_k_cache_rt(code, 10, rt_price)  # 获取最近的10日k线
        ave5 = ave_util.ave_line_price(k_line[0: 5], 5)  # 5日均线价格
        ave10 = ave_util.ave_line_price(k_line, 10)  # 10日均线价格
        stock_info['ave5'] = ave5
        stock_info['ave10'] = ave10
        stock_info['rt_price'] = rt_price
        stock_info['deal_time'] = date_util.get_date_time_str()
        stock_info['rq'] = current_date
        stock_info = score_service.common_exam(stock_info)  # 进行技术形态评分
        stock_info = trigger_service.deal_trigger(stock_info)  # 处理拐点和触发情况
        stock_info = record_into(stock_info)  # 记录交易状况
        stock_monitor_dict[code] = stock_info  # 刷新监控中信息
    send_msg()  # 发送用户消息提示
    update_local_monitor()  # 更新本地监控字典


# 更新分时k线图
def update_minute_k(stock_info):
    code = stock_info['code']
    rt_price = stock_info['rt_price']
    stock_info['deal_time'] = date_util.get_date_time_str()


# 开启监控定时任务
def monitor_up_down():
    # 初始化参数
    init_data()
    # 先执行一次再开启定时任务 方便一次启动监控
    monitor_up_down_v1()
    # 添加任务,时间间隔30S
    scheduler = BlockingScheduler()
    scheduler.add_job(monitor_up_down_v1, 'interval', seconds=frequency_config, id='monitor_up_down_v1')
    scheduler.start()


# 检查有效时间
def check_time():
    date_time = date_util.get_date_time()
    week_day = date_time.isoweekday()
    if week_day > 5:
        return 1
    hour = date_time.hour
    minute = date_time.minute
    if hour < 9 or hour >= 15:
        return 1
    if hour == 9 and minute < 30:
        return 1
    if (hour == 11 and minute >= 30) or hour == 12:
        return 1
    return 0


# 检查信息更新情况
def check_update():
    # 用户信息检查
    if users_service.update_flag():
        init_data()  # 重新初始化数据


# 发送消息提示
def send_msg():
    for user_code in users_dict:
        msg = ''
        for code in users_dict[user_code].keys():
            stock_info = stock_monitor_dict[code]
            # 提示间隔公式
            if 'prom_timestamp' not in stock_info.keys():
                continue
            stock_info = refresh_msg(stock_info)  # 更新消息提示
            diff_time = date_util.get_timestamp_now() - stock_info['prom_timestamp']
            cycle_count = int(diff_time / frequency_config)  # 几轮定时任务后
            if cycle_count in [0, 3, 9, 15, 30, 60, 480]:
                msg_info = stock_info['msg_info']
                for key in msg_info:
                    msg += key + msg_info[key]
                msg += '\n'
        # 处理消息
        msg_util.miao_msg(user_code, msg)


# 记录进入excel表中
def record_into(stock_info):
    rq = stock_info['rq']
    code = stock_info['code']
    name = stock_info['name']
    macd = stock_info['macd']
    ave5 = stock_info['ave5']
    ave10 = stock_info['ave10']
    rt_price = stock_info['rt_price']
    deal_flag = stock_info['deal_flag']
    deal_time = stock_info['deal_time']
    result_file_path = stock_info['result_file_path']

    # 新增记录方式 + 记录日志
    # 均线 + macd 触发记录
    if deal_flag != 0:
        stock_info = up_the_flow(stock_info)
        stock_info['prom_timestamp'] = date_util.datetime2timestamp(stock_info['deal_time'])
        logger.debug("triggerthedeal:" + str(stock_info))  # 记录日志数据分析使用

    if trigger_service.judge_flag(data=stock_info):
        if 'turn_form_last' in stock_info.keys():
            if stock_info['turn_form'] != stock_info['turn_form_last']:  # 形态发生变换
                stock_info = up_the_flow(stock_info)
                stock_info['turn_form_last'] = stock_info['turn_form']
                stock_info['trigger_timestamp'] = date_util.datetime2timestamp(stock_info['deal_time'])
                logger.debug("turningPoint:" + str(stock_info))  # 记录日志数据分析使用

    # 记录到excel
    if deal_flag != 0:
        stock_info = up_the_flow(stock_info)
        sb_io = stock_info['sb_io']
        b_io = stock_info['b_io']
        turnover_rate = stock_info['hsl']
        # 标题行
        content_arr = [['编码', '名称', '触发时间', '当前价格', '五日均线', '十日均线', '触发标志', 'MACD', '超大单净流入', '大单净流入', '换手率']]
        data = [code, name, deal_time, rt_price, ave5, ave10, deal_flag, macd, sb_io, b_io,
                turnover_rate]
        # 日志消息提示
        if deal_flag == 1 or deal_flag == 2:
            print("\033[32m$$$$$$$股票" + code + name + "突破均线")
        elif deal_flag == 3 or deal_flag == 4:
            print("\033[31m$$$$$$$股票" + code + name + "跌破均线")
        if ave5 > ave10:
            print(name + '最近为偏上升形态')
        else:
            print(name + '最近为偏下降形态')
        for num in range(len(data)):  # 打印数据日志
            print(str(num) + ':-----' + str(content_arr[0][num]) + ":" + str(data[num]))
        print("消息提示$$$$$$$$$$$$$$$结束\033[0m")
        file_path = os.path.join(result_path, rq, '触发记录', result_file_path)
        file_name = code + '-' + name + '.xlsx'
        # 保存到excel
        if not os.path.exists(os.path.join(file_path, file_name)):
            content_arr.append(data)
            excel_util.gen_an_excel(file_path, name + '-' + code, '', content_arr)
        else:
            excel_util.add_n_row(os.path.join(file_path, file_name), '', [data])

    return stock_info


# 更新资金流
def up_the_flow(stock_info):
    code = stock_info['code']
    if 'flow_up_time' in stock_info.keys():
        last_t = stock_info['flow_up_time']
        now_t = date_util.get_timestamp_now()
        if now_t - last_t > 100:  # 大于100秒更新
            flow = caiptal_util.get_flow(code)
            stock_info['sb_io'] = flow.sb_io
            stock_info['b_io'] = flow.b_io
            stock_info['hsl'] = flow.turnover_rate
            stock_info['flow_up_time'] = now_t
    else:
        flow = caiptal_util.get_flow(code)
        stock_info['sb_io'] = flow.sb_io
        stock_info['b_io'] = flow.b_io
        stock_info['hsl'] = flow.turnover_rate
        stock_info['flow_up_time'] = date_util.get_timestamp_now()
    return stock_info


def init_data():
    global stock_monitor_dict
    # 初始化
    monitor_list = doc_util.get_path_doc_info(os.path.join(document_path, 'stock_monitor_dict'))
    for monitor_info in monitor_list:
        monitor_info = json_util.info_to_json(monitor_info)
        stock_monitor_dict[monitor_info['code']] = monitor_info
    # 拼接用户数据
    global users_dict
    users_monitor_dict = {}
    file_names = doc_util.get_file_names(users_path)
    update_flag = 0
    if len(file_names) != 0:
        for file in file_names:
            stock_list = doc_util.get_path_doc_info(os.path.join(users_path, file))
            users_dict[file] = {}
            for stock_info in stock_list:
                stock_info = json_util.info_to_json(stock_info)
                if 'code' not in stock_info.keys():
                    continue
                code = stock_info['code']
                users_monitor_dict[code] = 'user'
                # 生成用户字典
                users_dict[file][code] = {'code': code}
                if code not in stock_monitor_dict.keys():
                    add_monitor(code)  # 加入监控字典
                    update_flag = 1
    # 虚拟持仓池
    virtual_monitor_dict = {}
    virtual_list = doc_util.get_path_doc_info(os.path.join(document_path, 'stock_virtual_hold'))
    for virtual_info in virtual_list:
        virtual_info = json_util.info_to_json(virtual_info)
        code = virtual_info['code']
        virtual_monitor_dict[code] = 'virtual'
        if code not in stock_monitor_dict.keys():
            add_monitor(code)  # 增加持仓
            update_flag = 1
    # 清理不需要的监控
    del_code_list = []
    for code in stock_monitor_dict.keys():
        if (code not in users_monitor_dict) \
                and (code not in virtual_monitor_dict):
            del_code_list.append(code)
            update_flag = 1
    for code in del_code_list:
        stock_monitor_dict.pop(code)
    if update_flag: update_local_monitor()  # 持久化监控字典 #后期用es优化
    users_service.del_flag()  # 删除标记文件


def update_local_monitor():
    doc_util.gen_a_doc(document_path, 'stock_monitor_dict', stock_monitor_dict)


def add_monitor(code):
    global stock_monitor_dict
    # 初始化
    k_lines = k_util.day_k_local(code, 10)
    ave5 = ave_util.ave_line_price(k_lines[5:10], 5)
    ave10 = ave_util.ave_line_price(k_lines, 10)
    sp_pre = float(json_util.info_to_json(k_lines[9])['sp'])
    flag5 = 1  # 1:监控突破 -1:监控跌破 初始化
    flag10 = 1  # 1:监控突破 -1:监控跌破 初始化
    if sp_pre > ave5: flag5 = -1
    if sp_pre > ave10: flag10 = -1
    deal_flag = 0  # 交易标志 deal_flag = 0  # 0:初始化 1:全仓 2:加半仓 3:清仓 4:减半仓
    monitor_info = {}
    monitor_info['msg'] = ''  # 提示消息
    monitor_info['code'] = code
    monitor_info['ave5'] = ave5
    monitor_info['ave10'] = ave10
    monitor_info['flag5'] = flag5
    monitor_info['flag10'] = flag10
    monitor_info['deal_flag'] = deal_flag
    monitor_info['name'] = stock_dict[code]['name']
    monitor_info['exchange'] = stock_dict[code]['exchange']
    monitor_info['insert_time'] = date_util.get_date_time_str()
    monitor_info['result_file_path'] = '未分类'  # 存储分类路径
    monitor_info['last_deal_time'] = '2000-01-01 00:00:00'  # 最新交易(触犯)日期
    stock_monitor_dict[code] = monitor_info


# 刷新消息
def refresh_msg(stock_info):
    print('开始刷新消息')
    code = stock_info['code']
    stock_info = up_the_flow(stock_info)
    msg_dict = {}
    msg_dict['\n名称:'] = stock_info['name']
    msg_dict[',编码:'] = code
    msg_dict['\n触发时间:'] = stock_info['trigger_time']
    msg_dict['\n当前macd形态:'] = '"' + stock_info['macd'] + '"'
    if 'deal_price' in stock_info.keys():
        msg_dict['\n触发价格:'] = str(stock_info['deal_price'])
    msg_dict['\n当前价格:'] = str(stock_info['rt_price'])
    msg_dict['\n5日均线价:'] = str(stock_info['ave5'])
    msg_dict['\n10日均线价:'] = str(stock_info['ave10'])
    msg_dict['\n超大单净流入:'] = str(int(stock_info['sb_io'] / 10000)) + '万'
    msg_dict['\n大单净流入:'] = str(int(stock_info['b_io'] / 10000)) + '万'
    msg_dict['\n换手率:'] = str(stock_info['hsl'])
    msg_dict['\n触发标志:'] = stock_info['result_file_path']
    stock_info['msg_info'] = msg_dict
    return stock_info

if __name__ == '__main__':
    # refresh_dict()
    monitor_up_down()
